package com.randb.easyhttp.request;

import com.google.gson.reflect.TypeToken;
import com.randb.easyhttp.cache.model.CacheResult;
import com.randb.easyhttp.callback.CallClazzProxy;
import com.randb.easyhttp.callback.Callback;
import com.randb.easyhttp.callback.CallbackProxy;
import com.randb.easyhttp.func.ApiResultFunc;
import com.randb.easyhttp.func.CacheResultFunc;
import com.randb.easyhttp.func.RetryExceptionFunc;
import com.randb.easyhttp.model.ApiResult;
import com.randb.easyhttp.subscriber.CallbackSubscriber;
import com.randb.easyhttp.utils.RxUtils;

import java.lang.reflect.Type;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.disposables.Disposable;
import okhttp3.ResponseBody;

/**
 * User: RandBII
 * Date: 2020/5/27
 * Description:
 */
@SuppressWarnings("Unchecked")
public class GetRequest extends BaseRequest<GetRequest> {


    public GetRequest(String url) {
        super(url);
    }


    @Override
    protected Observable<ResponseBody> generateRequest() {
        return apiManager.get(url, params.urlParamsMap);
    }


    public <T> Observable<T> execute(Class<T> clazz) {
        return execute(new CallClazzProxy<ApiResult<T>, T>(clazz) {
        });
    }

    public <T> Observable<T> execute(Type type) {
        return execute(new CallClazzProxy<ApiResult<T>, T>(type) {
        });
    }


    public <T> Observable execute(CallClazzProxy<ApiResult<T>, T> proxy) {
        return build().generateRequest()
                .map(new ApiResultFunc(proxy.getType()))
                .compose(isSyncRequest ? RxUtils._main() : RxUtils._io_main())
                .compose(rxCache.transformer(cacheMode, proxy.getType()))
                .retryWhen(new RetryExceptionFunc(retryCount, retryDelay, retryIncreaseDelay))
                .compose(new ObservableTransformer() {
                    @Override
                    public ObservableSource apply(Observable upstream) {
                        return upstream.map(new CacheResultFunc<T>());
                    }
                });

    }

    public <T> Disposable execute(Callback<T> callback) {
        return execute(new CallbackProxy<ApiResult<T>, T>(callback) {
        });
    }


    public <T> Disposable execute(CallbackProxy<? extends ApiResult<T>, T> proxy) {
        Observable<CacheResult<T>> observable = build()
                .toObservable(apiManager.get(url, params.urlParamsMap), proxy);
        if (CacheResult.class != proxy.getCallback().getType()) {
            return observable.compose(new ObservableTransformer<CacheResult<T>, T>() {
                @Override
                public ObservableSource<T> apply(Observable<CacheResult<T>> upstream) {
                    return upstream.map(new CacheResultFunc<T>());
                }
            }).subscribeWith(new CallbackSubscriber<T>(context, proxy.getCallback()));
        } else {
            return observable.subscribeWith(new CallbackSubscriber<CacheResult<T>>(context, proxy.getCallback()));
        }

    }

    @SuppressWarnings("unchecked")
    protected <T> Observable<CacheResult<T>> toObservable(Observable<ResponseBody> observable,
                                                          CallbackProxy<? extends ApiResult<T>, T> proxy) {

        return observable.map(new ApiResultFunc(proxy.getType() != null ? proxy.getType() : new TypeToken<ResponseBody>() {
        }.getType()))
                .compose(isSyncRequest ? RxUtils._main() : RxUtils._io_main())
                .compose(rxCache.transformer(cacheMode, proxy.getCallback().getType()))
                .retryWhen(new RetryExceptionFunc(retryCount, retryDelay, retryIncreaseDelay));

    }


}
